home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / PROGRAMM / CC_C / 0151.ZIP / BUG208.ASM < prev    next >
Assembly Source File  |  1985-07-30  |  40KB  |  2,026 lines

  1. title Fido's Bugger
  2. name bugger
  3. ;
  4. ;****************************************
  5. ;*                    *
  6. ;*            Bugger             *
  7. ;*                    *
  8. ;*    For: Fido            *
  9. ;*                    *
  10. ;*    T. Jennings 30 July 85        *
  11. ;*     created 29 April 81        *
  12. ;*                    *
  13. ;****************************************
  14. ;
  15. cgroup group code
  16. dgroup group data
  17. ;
  18. ;   This debugger and boot rom supports the
  19. ;following hardware:
  20. ;
  21. ;Intel SBC 86/12:
  22. ;    Console on the serial port,
  23. ;    9600 baud, no parity, 8 bits
  24. ;Memory:
  25. ;    64K minimum; buggers stack and
  26. ;    work space is at 0f80:0000.
  27. ;    Disk boot sector loaded at 10:0
  28. ;Diskettes:
  29. ;    Intel iSBC-208 at port 40h.
  30. ;    8" and 5" diskettes. AUX port
  31. ;    bits controlling motor, etc.
  32. ;Hard Disk:
  33. ;    A Xebec Controller on a DTC Host
  34. ;    Interface, supporting a typical
  35. ;    10 meg wini, drive type = 4.
  36. ;Other:    A loudspeaker tied to bit 0 of 
  37. ;    the 8255 Port C. 
  38. ;
  39. ;  Bugger inits the hardware needed to boot,
  40. ;some interrupt vectors, then autoboots the
  41. ;hard disk (A:). It makes funny noises while
  42. ;booting.
  43. ;
  44. ;  If Control-C is hit, bugger jumps into
  45. ;command mode; see BUGGER.DOC for details.
  46. ;
  47. ;
  48. ;The power on jump at FFFF:0000 must be
  49. ;patched into the ROMs after burning this
  50. ;code:
  51. ;
  52. ;2716's (2K)
  53. ;
  54. ;EVEN PROM: 07f8: ea 00 fe
  55. ;ODD PROM:  07f8: 00 00
  56. ;
  57. ;2732's (4K)
  58. ;
  59. ;EVEN PROM: 0ff8: ea 00 ff
  60. ;ODD PROM:  0ff8: 00 00
  61. ;
  62. ;What is being patched in is:
  63. ;
  64. ;    jmp far 0fe00:0000 ;(2716)
  65. ;    jmp far 0ff00:0000 ;(2732)
  66. ;
  67. ;Baud rate for the serial port
  68. ;
  69. baud_rate equ    9600    
  70. baud    equ    768 / (baud_rate / 100)
  71. ;
  72. ;Where our data segment is:
  73. ;
  74. dataseg    equ    0f80h
  75. page
  76. ;
  77. ;Interrupts used:
  78. ;
  79. ;
  80. ;Floppy disk read interrupt: A standard Fido
  81. ;disk BIOS table at DS:BX. Status in AL; carry
  82. ;if error. These vectors must be below 00100h,
  83. ;or 0010:0000, since thats where the boot is
  84. ;loaded, and the 1K boot sector wipes out the
  85. ;interrupt vectors.
  86. ;
  87. FLP_INT    equ    32    ;floppy access
  88. RMS_INT    equ    33    ;hard disk access
  89.  
  90. TRC_INT    equ    1    ;single step
  91. BRK_INT    equ    3    ;break point
  92. BRK_INST equ    0cch    ;INT 3
  93. CR    equ    0dh    ;carriage return
  94. LF    equ    0ah    ;line feed 
  95.  
  96. include iodef.ash
  97. include disk.ash
  98. include disk2.ash
  99. page
  100. ;
  101. ;Where we load the boot sector. This is
  102. ;in the middle of the interrupt vectors,
  103. ;and it assumes the boot sector isnt big
  104. ;enough to trash our vectors.
  105. ;
  106. bootseg    segment    at 10h
  107.     org    0
  108. boot label far
  109. bootseg    ends
  110. ;
  111. ;Start of ROM code. cgroup must be
  112. ;first so the linker will put things in
  113. ;the right order.
  114. ;
  115. code segment byte public 'code'
  116. assume cs:cgroup
  117.  
  118. bugger:    jmp    start
  119. ;
  120. ;Old interface. Do not use it.
  121. ;
  122. interface proc far
  123.     call    ina
  124.     ret
  125.     call    outa
  126.     ret
  127.     call    foo        ;deleted call,
  128.     ret            ;dummy out.
  129.     call    execute
  130.     ret
  131.     call    dtc
  132.     ret
  133. ;
  134. ;New interface, accessed by the software
  135. ;interrupts. Call the ROM code,return, 
  136. ;trashing the flags.
  137. ;
  138. hboot:    call    dtc
  139.     ret    2
  140.  
  141. fboot:    call    execute
  142.     ret    2
  143.  
  144. interface endp
  145.  
  146. foo:    ret
  147.  
  148. code ends
  149.  
  150. data segment byte public 'data'
  151.  
  152. stack     dw    (?)
  153. ;
  154. ;Work space for the DTC/Xebec controller
  155. ;drivers and initialization.
  156. ;
  157. cmdtbl db 9 dup (?)
  158. dattbl db 8 dup (?)
  159. ;
  160. ;DTC/Xebec command string.
  161. ;
  162. xcomand    db    (?)    ;command,
  163. lun    db    (?)    ;unit, top sector,
  164. hiaddr    db    (?)    ;high sec byte,
  165. lowaddr    db    (?)    ;low sec byte,
  166. scount    db    (?)    ;sector count,
  167. control    db    (?)
  168.     db 8 dup (?)
  169. ;
  170. ;breakpoint and    go register save/display area
  171. ;these register    save locations must be kept in 
  172. ;this order.
  173. ;
  174. dmp_ptr    label word
  175. brkfl    dw    (?)        ;saved flags
  176. brkax    dw    (?)        ;saved ax
  177. brkbx    dw    (?)        ;saved bx
  178. brkcx    dw    (?)        ;saved cx
  179. brkdx    dw    (?)        ;saved dx
  180. brksi    dw    (?)        ;saved si
  181. brkdi    dw    (?)        ;saved di
  182. brksp    dw    (?)        ;saved sp
  183. brkip    dw    (?)        ;saved ip
  184. ip_base    dw    (?)        ;reloc reg
  185. brkcs    dw    (?)
  186. brkds    dw    (?)
  187. brkes    dw    (?)
  188. brkss    dw    (?)
  189. brkbp    dw    (?)        ;base pointer
  190. ;
  191. ;More data area. These don't have to be in
  192. ;any specific order.
  193. ;
  194. noreloc    db    (?)        ;no relocation
  195. dmpoff    dw    (?)        ;display addr
  196. dmpseg    dw    (?)        ;local ES
  197. scratch    db    (?)        ;scratch word,
  198. bootnum    dw    (?)        ;default drive,
  199. ;
  200. ;Breakpoint data.
  201. ;
  202. brkflg    db    (?)        ;true if break
  203. brkadr    dw    (?)        ;brk pnt addr
  204. brkseg    dw    (?)        ;brk pnt seg
  205. brkinst    db    (?)        ;saved inst
  206. data ends
  207.  
  208. page
  209. code segment byte public 'code'
  210. assume cs:cgroup,ds:dgroup
  211. ;
  212. ;Data word to set DS.
  213. ;
  214. dataloc    dw    dataseg
  215. ;
  216. ;Data tables here, to avoid MASM bugs.
  217. ;
  218. ctable    db      'g'
  219.     dw    offset go
  220.     db    'x'
  221.     dw    offset registers;dump regs
  222.     db    'r'
  223.     dw    offset registers
  224.     db    's'
  225.     dw    offset memchg    ;change    memory
  226.     db    'e'
  227.     dw    offset memchg    ;ditto
  228.     db    'd'
  229.     dw    offset dump    ;dump memory
  230.     db    'f'
  231.     dw    offset fill    ;fill memory,
  232.     db    'm'
  233.     dw    offset blkmov    ;move memory.
  234.     db    'i'
  235.     dw    offset input    ;port input
  236.     db    'o'
  237.     dw    offset output    ;port output.
  238.     db    't'
  239.     dw    offset trace    ;trace command,
  240.     db    'h'
  241.     dw    offset arith    ;do arithmetic
  242.     db    'l'
  243.     dw    offset intel    ;load hex,
  244.     db    'v'
  245.     dw    offset intvec    ;fiddle int vec
  246.     db    'b'
  247.     dw     offset dboot    ;disk boot
  248. page
  249. eh    db    ' eh?',0
  250. id1str    db CR,"Fido's Bugger, 30 July 85"
  251. id2str    db CR,"Booting from drive A:, "
  252.     db " Control-C to abort: ",0
  253. dskstr    db CR,"Disk read error",0
  254. butstr    db CR,"Bad boot sector",0
  255.  
  256. prompt    db    CR,'Ok.',0
  257.  
  258. regstr1    db CR,'ax   bx   cx   dx   si   di   '
  259.     db    'sp   ip + rr   ',CR,0
  260.  
  261. regstr2    db CR,'cs   ds   es   ss   bp   TOS  '
  262.     db    'NOS  ....oditsz.a.p.c',CR,0
  263.  
  264. regtbl    dw    'fl','ax','bx','cx','dx','si'
  265.     dw    'di','sp','ip','rr','cs'
  266.     dw    'ds','es','ss','bp'
  267. rtblen    equ    ($ - regtbl) / 2
  268. page
  269. ;
  270. ;Disk boot read    tables. These are the
  271. ;standard Fido MSDOS BIOS disk tables. ALl
  272. ;boot sectors are track 0 sector 1. (First
  273. ;sector, damn IBM)
  274. ;
  275. ;Shugart 850, drive 0, DD1024 single sided,
  276. ;double density, eight 1024 byte sectors, 
  277. ;77 tracks.
  278. ;
  279. dd1024    db    fread    ;read command, 
  280.     db    0    ;drive 0,
  281.     dw    0    ;track 0,
  282.     dw    1    ;sector    1,
  283.     dw    1    ;1 sector,
  284.     dw    -1    ;current track unknown
  285.     db    1    ;double density,
  286.     db    15    ;gap length,
  287.     db    3    ;sec size,
  288.     db    255    ;data len,
  289.     dw    1024    ;sector    size,
  290.     dw    0    ;DMA offset,
  291.     dw    10h    ;DMA segment,
  292.     dw    8    ;sectors/track
  293.     dw    0    ;head 0,
  294. dblen equ $ - dd1024
  295. ;
  296. ;Shugart 850, SD128 single sided single
  297. ;density 26 128 byte sectors per track.
  298. ;
  299. sd128    db    fread    ;read command, 
  300.     db    0    ;drive 0,
  301.     dw    0    ;track 0,
  302.     dw    1    ;sector    1,
  303.     dw    1    ;1 sector,
  304.     dw    -1    ;current track unknown
  305.     db    0    ;single density,
  306.     db    0    ;gap length,
  307.     db    0    ;sec size,
  308.     db    0    ;data len,
  309.     dw    128    ;sector    size,
  310.     dw    0    ;DMA offset,
  311.     dw    10h    ;DMA segment,
  312.     dw    26
  313.     dw    0
  314. ;
  315. ;Tandon DMIBM8-1 single sided double density
  316. ;eight 512 byte sectors per track, 40 tracks.
  317. ;
  318. ibm    db    fread    ;read command, 
  319.     db    2    ;drive 2,
  320.     dw    0    ;track 0,
  321.     dw    1    ;sector    1,
  322.     dw    1    ;1 sector,
  323.     dw    -1    ;current track unknown
  324.     db    3    ;double density mini
  325.     db    0    ;gap length,
  326.     db    0    ;sec size,
  327.     db    0    ;data len,
  328.     dw    512    ;sector    size,
  329.     dw    0    ;DMA offset,
  330.     dw    10h    ;DMA segment,
  331.     dw    8    ;spt
  332.     dw    0    ;head
  333. page
  334. ;RMS, HD256 8 heads 32 256 byte sectors/track,
  335. ;logically arranged as 192 spt.
  336. ;
  337. rms    db    fread    ;read command, 
  338.     db    0    ;drive 0,
  339.     dw    0    ;track 0,
  340.     dw    1    ;sector    1,
  341.     dw    1    ;1 sector,
  342.     dw    -1    ;current track unknown
  343.     db    0
  344.     db    0    ;gap length,
  345.     db    0    ;sec size,
  346.     db    0    ;data len,
  347.     dw    256    ;sector    size,
  348.     dw    0    ;DMA offset,
  349.     dw    10h    ;DMA segment,
  350.     dw    192    ;spt
  351.     dw    0
  352. ;
  353. ;Same as above, table for interrogating
  354. ;drive ready only.
  355. ;
  356. rmsc    db    fcheck    ;read command, 
  357.     db    0    ;drive 0,
  358.     dw    0    ;track 0,
  359.     dw    1    ;sector    1,
  360.     dw    1    ;1 sector,
  361.     dw    -1    ;current track unknown
  362.     db    0
  363.     db    0    ;gap length,
  364.     db    0    ;sec size,
  365.     db    0    ;data len,
  366.     dw    256    ;sector    size,
  367.     dw    0    ;DMA offset,
  368.     dw    10h    ;DMA segment,
  369.     dw    192    ;spt
  370.     dw    0    ;head
  371. page
  372. ;
  373. ;Sound tables, for a 8253 clock rate
  374. ;of 1.23 MHz.
  375. ;
  376. OCTAVE    equ    2
  377.  
  378. CNOTE    equ    9609    ;C
  379. CSNOTE    equ    9044    ;C#
  380. DNOTE    equ    8541    ;D
  381. DSNOTE    equ    8092    ;D#
  382. ENOTE    equ    7687    ;E
  383. FNOTE    equ    6988    ;F
  384. FSNOTE    equ    6684    ;F#
  385. GNOTE    equ    6406    ;G
  386. GSNOTE    equ    5913    ;G#
  387. ANOTE    equ    5694    ;A
  388. ASNOTE    equ    5301    ;A#
  389. BNOTE    equ    4959    ;B
  390. NONOTE    equ    0    ;no tone
  391. ENDNOTE    equ    -1    ;end of list
  392.  
  393. EIGHTH    equ    20
  394. QUARTER    equ    2 * EIGHTH
  395. HALF    equ    2 * QUARTER
  396. FULL    equ    2 * HALF
  397. ;
  398. ;Something wrong
  399. ;
  400. fault label word
  401.     dw    NONOTE,QUARTER
  402.     dw    DNOTE,QUARTER
  403.     dw    DSNOTE,HALF
  404.     dw    CNOTE,QUARTER
  405.     dw    CSNOTE,HALF
  406.     dw    DNOTE,QUARTER
  407.     dw    DSNOTE,HALF
  408.     dw    CNOTE,QUARTER
  409.     dw    CSNOTE,HALF
  410.     dw    ENDNOTE
  411. ;
  412. ;Power up, alive.
  413. ;
  414. alive label word
  415.     dw    CNOTE,QUARTER
  416.     dw    ANOTE,QUARTER
  417.     dw    GNOTE,QUARTER
  418.     dw    ENOTE,QUARTER
  419.     dw    NONOTE,QUARTER
  420.     dw    CNOTE,QUARTER
  421.     dw    ANOTE,QUARTER
  422.     dw    GNOTE,QUARTER
  423.     dw    ENOTE,QUARTER
  424.     dw    NONOTE,QUARTER
  425.     dw    ENDNOTE
  426. ;
  427. ;While trying to boot
  428. ;
  429. bootsong label word
  430.     dw    ANOTE,HALF
  431.     dw    FSNOTE,HALF
  432.     dw    ENOTE,HALF
  433.     dw    DNOTE,HALF
  434.     dw    NONOTE,HALF
  435.     dw    ENDNOTE
  436. ;
  437. ;Boot loaded, running DOS
  438. ;
  439. dostune label word
  440.     dw    CNOTE,QUARTER
  441.     dw    DNOTE,QUARTER
  442.     dw    ENOTE,QUARTER
  443.     dw    FNOTE,QUARTER
  444.     dw    GNOTE,QUARTER
  445.     dw    BNOTE,QUARTER
  446.     dw    ENDNOTE
  447. ;
  448. ;Bugger command error
  449. ;
  450. blatz label word
  451.     dw    DNOTE,EIGHTH
  452.     dw    DSNOTE,EIGHTH
  453.     dw    CNOTE,EIGHTH
  454.     dw    CSNOTE,EIGHTH
  455.     dw    ENDNOTE
  456. page
  457. ;
  458. ;Set things up, init the hardware, try
  459. ;to boot.
  460. ;
  461. start:    mov    ss,cs:dataloc
  462.     mov    sp,offset stack
  463.     mov    ds,cs:dataloc
  464.  
  465.     call    IOINIT        ;clear hardware
  466.     mov    bx,offset alive
  467.     call    play        ;make noise
  468.  
  469.     mov    ax,0
  470.     mov    ds,ax        ;install int
  471.  
  472.     mov    bx,BRK_INT * 4
  473.     mov    word ptr [bx],offset brkntr
  474.     mov    bx,BRK_INT * 4 + 2
  475.     mov    word ptr [bx],cs
  476.     mov    bx,TRC_INT * 4
  477.     mov    word ptr [bx],offset brkntr
  478.     mov    bx,TRC_INT * 4 + 2
  479.     mov    word ptr [bx],cs
  480.     mov    bx,FLP_INT * 4
  481.     mov    word ptr [bx],offset fboot
  482.     mov    bx,FLP_INT * 4 + 2
  483.     mov    word ptr [bx],cs
  484.     mov    bx,RMS_INT * 4
  485.     mov    word ptr [bx],offset hboot
  486.     mov    bx,RMS_INT * 4 + 2
  487.     mov    word ptr [bx],cs
  488.  
  489.     mov    ds,cs:dataloc
  490.     mov    ip_base,0
  491.     mov    brkflg,0
  492.     mov    brkds,ds
  493.     mov    brkss,ss
  494.     mov    brksp,sp
  495.  
  496.     mov    bx,offset id1str
  497.     call    pstr
  498. ;
  499. ;Wait until the disk is ready, then boot it.
  500. ;If Control-C is typed, jump into bugger.
  501. ;
  502.     mov    ax,cs        ;disk tables in
  503.     mov    ds,ax        ;code seg
  504. b11:    mov    bx,offset bootsong
  505.     call    play        ;chance to hit
  506.     call    inastat        ;Control-C
  507.     jz    b13
  508.     call    ina
  509.     cmp    al,3
  510.     jne    b13
  511.     mov    bx,offset fault    
  512.     call    play        ;make noise
  513.     jmp    warm        ;exit if ^C
  514.  
  515. b13:    mov    bx,offset rmsc    ;check for
  516.     int    RMS_INT        ;drive ready
  517.     jc    b11
  518.  
  519.     mov    bx,offset rms    ;attempt to 
  520.     int    RMS_INT        ;read the boot
  521.     jnc    b20
  522.     mov    bx,offset dskstr;if error,
  523.     call    pstr        ;nasty message
  524.     mov    bx,offset fault
  525.     call    play
  526.     jmp    b11
  527.  
  528. b20:    mov    ax,bootseg    ;read OK,
  529.     mov    ds,ax        ;make sure it's
  530.     mov    bx,0        ;really a boot
  531.     mov    al,[bx]        ;sector,
  532.     cmp    al,0fah        ;(CLI)
  533.     je    b21        ;if not,
  534.     mov    bx,offset butstr
  535.     call    pstr
  536.     mov    bx,offset fault
  537.     call    play
  538.     jmp    b11
  539.  
  540. b21:    mov    bx,offset dostune
  541.     call    play
  542.     mov    cx,0        ;drive A:,
  543.     jmp    boot        ;boot system.
  544. page
  545. ;
  546. ;This is the main command loop,    where commands 
  547. ;are input, etc. Any user type errors get here 
  548. ;also. Some commands that cannot maintain stack
  549. ;discipline, such as return from break point, 
  550. ;jump here. Look up single letter commands 
  551. ;input from the    console, in the    command    table.
  552. ;If we find one, go execute it,    else barf.
  553. ;
  554. warm:    mov    ss,cs:dataloc
  555.     mov    sp,offset stack
  556.     mov    ds,cs:dataloc    ;set our DS,
  557.     mov    es,dmpseg    ;and ES,
  558.  
  559. wig:    mov    bx,offset prompt ;type prompt,    
  560.     call    pstr        ;string in CS:
  561.     call    charin        ;get command 
  562.     jz    wig        ;ignore    delims
  563.  
  564.     mov    bx,offset ctable;table search,
  565. warma:    mov    ah,cs:[bx]    ;table entry
  566.     mov    cx,cs:[bx + 1]    ;call addr
  567.     add    bx,3        ;next ...
  568.     cmp    ah,0        ;end of table?
  569.     je    error
  570.     cmp    ah,al        ;command key?
  571.     jne    warma
  572.     call    cx        ;call it,
  573.     jmp    warm        ;repeat.
  574. ;
  575. ;General purpose error handler.    not real 
  576. ;graceful.
  577. ;
  578. error:    mov    ss,cs:dataloc
  579.     mov    sp,offset stack
  580.     mov    bx,offset eh    ;nasty msg,
  581.     call    pstr
  582.     mov    bx,offset blatz
  583.     call    play
  584.     jmp    warm
  585. page
  586. ;
  587. ;Trace command.    Set the    Trace flag in the flag
  588. ;register, then    execute like a 'go'.
  589. ;
  590. trace:    or    brkfl,0000000100000000b
  591.     jmp    gonow        ;go execute,
  592. ;
  593. ;Go with or without breakpoint. If a comma is
  594. ;entered, get a breakpoint address, else just
  595. ;execute.
  596. ;
  597. go:    and    brkfl,1111111011111111b
  598.     mov    es,brkcs    ;set 'go' seg
  599.     mov    dmpseg,es    ;and in ES,
  600.     mov    bx,brkip    ;and 'go' off
  601.     mov    dmpoff,bx
  602.     call    getadr        ;for 'getadr'
  603.     mov    brkip,bx    ;set brk IP,
  604.     mov    brkcs,es    ;and seg,
  605.     cmp    al,','        ;if a comma, 
  606.     jne    gonow        ;breakpoint,
  607. ;
  608. ;The start addr is set, and a comma was typed.
  609. ;Get the breakpoint addr, put an INT 3 there
  610. ;and save the instruction.
  611. ;
  612. gobrk:    call    getadr        ;get brk addr
  613.     mov    brkadr,bx    ;save brk adr
  614.     mov    brkseg,es
  615.     mov    al,BRK_INST
  616.     xchg    al,es:[bx]    ;set brk inst,
  617.     mov    brkinst,al    ;save old inst
  618.     mov    brkflg,1    ;set flag,
  619. ;
  620. ;Restore regs and return.
  621. ;
  622. gonow:    cli            ;no ints,
  623.     mov    ax,brkax
  624.     mov    bx,brkbx    ;restore a
  625.     mov    cx,brkcx    ;bunch of regs
  626.     mov    dx,brkdx
  627.     mov    di,brkdi
  628.     mov    si,brksi
  629.     mov    bp,brkbp
  630.     mov    ss,brkss    ;set SS and
  631.     mov    sp,brksp    ;stack pointer,
  632.     push    brkfl        ;push flags,
  633.     push    brkcs        ;far address,
  634.     push    brkip
  635.     mov    es,brkes    ;restore ES,
  636.     mov    ds,brkds    ;and DS,
  637.     iret            ;call address
  638. page
  639. ;
  640. ;Breakpoint entry. Executed only via a jump 
  641. ;from the restart location.  Breakpoints 
  642. ;require lots of the users stack. All registers
  643. ;are saved and displayed. 
  644. ;
  645. ;Decrement the go counter; if not zero yet,
  646. ;display the regs and go reexecute from there.
  647. ;
  648. brkntr:    push    ds
  649.     mov    ds,cs:dataloc    ;set DS,
  650.     pop    brkds        ;save DS,
  651.     pop    brkip        ;IP,
  652.     pop    brkcs        ;CS,
  653.     pop    brkfl        ;flags,
  654.  
  655.     mov    brkax,ax    ;save regs,
  656.     mov    brkbx,bx
  657.     mov    brkcx,cx
  658.     mov    brkdx,dx
  659.     mov    brksi,si
  660.     mov    brkdi,di
  661.     mov    brkbp,bp
  662.     mov    brkes,es
  663.     mov    brkss,ss
  664.     mov    brksp,sp
  665.  
  666.     mov    ss,cs:dataloc    ;set stack,
  667.     mov    sp,offset stack
  668.     sti            ;enable ints,
  669.  
  670.     mov    ax,brkip    ;set variables
  671.     mov    dmpoff,ax    ;for debug,
  672.     mov    ax,brkcs
  673.     mov    dmpseg,ax
  674.  
  675.     test    brkflg,1    ;breakpoint?
  676.     jz    bknbh        ;return if not.
  677.         dec    brkip    ;put pc    back 
  678.         mov    bx,brkadr ;restore the
  679.         mov    es,brkcs  ;instruction
  680.         mov    al,brkinst
  681.         mov    es:[bx],al
  682. bknbh:    mov    brkflg,0    ;no more brkpt
  683.     call    regdmp        ;dump the regs
  684.     jmp    warm        ;and stop.
  685. page
  686. ;
  687. ;Register control command. X<CR,comma,space> 
  688. ;displays  all registers.  X<reg name> displays
  689. ;the current register value, and allows    
  690. ;entering al new value.    The legal register 
  691. ;names are in al table in the byte section.     
  692. ;
  693. registers:
  694.     call    charin
  695.     je    regdmp        ;Z set if delim
  696.     jmp    regchg        ;if not    a delim
  697. regdmp:    mov    bx,offset regstr1 ;type    top lin
  698.     call    pstr        ;of the display
  699.     mov    bx,brkax
  700.     call    outhex        ;type ax,    
  701.     mov    bx,brkbx
  702.     call    outhex        ;type bx,space
  703.     mov    bx,brkcx
  704.     call    outhex        ;type cx,space
  705.     mov    bx,brkdx
  706.     call    outhex        ;type bx,spaces
  707.     mov    bx,brksi
  708.     call    outhex        ;si, spaces,
  709.     mov    bx,brkdi
  710.     call    outhex        ;di, spaces,
  711.     mov    bx,brksp
  712.     call    outhex        ;type sp
  713.     mov    bx,brkip    ;type IP,
  714.     sub    bx,ip_base    ;minus offset,
  715.     call    outhex
  716.  
  717.     mov    bx,ip_base
  718.     call    outhex        ;reloc reg,
  719.  
  720.     mov    bx,offset regstr2 ;next    line,
  721.     call    pstr
  722.     mov    bx,brkcs    ;type seg regs
  723.     call    outhex
  724.     mov    bx,brkds
  725.     call    outhex
  726.     mov    bx,brkes
  727.     call    outhex
  728.     mov    bx,brkss
  729.     call    outhex
  730.     mov    bx,brkbp    ;and the BP reg
  731.     call    outhex
  732.  
  733.     mov    es,brkss    ;get two top 
  734.     mov    si,brksp    ;stack values,
  735.     cld
  736.     mov    bx,es:[si]
  737.     call    outhex        ;type TOS,
  738.     mov    bx,es:[si+2]
  739.     call    outhex        ;then NOS,
  740.  
  741.     mov    ax,brkfl
  742.     call    axtobin        ;type flags,
  743.     ret
  744. page
  745. ;
  746. ;Modify    pseudo registers. The registers    are 
  747. ;hardcoded in the same order as they appear in
  748. ;RAM. AL contains the first letter of the 
  749. ;register, get the second letter in AH,    then 
  750. ;look it up.    
  751. ;
  752. regchg:    mov    ah,al
  753.     call    charin
  754.     cmp    ax,'ip'        ;special case
  755.     je    regip        ;IP,
  756.  
  757.     mov    si,offset regtbl ;reg names,
  758.     mov    bx,offset dmp_ptr; reg values,
  759.     mov    cx,rtblen    ;table length,
  760. rchal:    cmp    ax,cs:[si]    ;match?
  761.     je    pair        ;go change.
  762.     add    si,2        ;next...
  763.     add    bx,2
  764.     loop    rchal
  765.     jmp    ERROR        ;none!
  766. ;
  767. ;Change    a word in memory.
  768. ;
  769. pair:    mov    cx,[bx]        ;get value,
  770.     xchg    bx,cx        ;to BX,
  771.     call    xreg        ;change it,
  772.     xchg    cx,bx        ;to CX,
  773.     mov    [bx],cx        ;update.
  774.     ret
  775. ;
  776. ;Display a value, and get a new    one.
  777. ;
  778. xreg:    call    outhex        ;display it,
  779.     mov    al,'='
  780.     call    charout
  781.     call    inhex        ;get a new one.
  782.     ret
  783. ;
  784. ;Register IP. Display current IP minus 
  785. ;'ip_base', add it in when storing it.
  786. ;
  787. regip:    mov    bx,brkip
  788.     sub    bx,ip_base    ;adjust,
  789.     call    xreg        ;change,
  790.     add    bx,ip_base    ;adjust again,
  791.     mov    brkip,bx    ;store.
  792.     ret
  793. page
  794. ;
  795. ;display memory    as 8 lines of 16 bytes,
  796. ;followed by 16    of ASCII. es: is our data 
  797. ;segment pointer.
  798. ;
  799. dump:    call    getadr        ;get address,
  800.     mov    cx,8        ;do i= 1,8
  801. dmpal:        call    crlf    ;newline,
  802.         call    outadr    ;type addr,
  803.         push    cx    ;save count,
  804.         mov    cx,16    ;do j=1,16
  805.         push    bx    ;save for ASCII
  806. dmpbh:            mov    al,es:[bx]
  807.             call    out2h
  808.             inc    bx
  809.             mov    dmpoff,bx
  810.         loop    dmpbh    ;do 16 bytes
  811.  
  812.         pop    bx    ;now dump ASCII
  813.         mov    cx,16
  814. dmpbl:            mov    al,es:[bx]
  815.             inc    bx ;same bytes,
  816.             and    al,7fh
  817.             cmp    al,' '
  818.             jae    dmpd
  819.             mov    al,'_'
  820. dmpd:            call    charout
  821.         loop    dmpbl
  822.     pop    cx        ;get line count
  823.     loop    dmpal        ;next line,
  824.     ret
  825. page
  826. ;
  827. ;Examine/change    memory.    An address is entered, 
  828. ;and  bytes are    displayed after    the address. 
  829. ;New values may    be entered, or the left    
  830. ;unchanged by typing only al delimiter.    Comma 
  831. ;and space close the current location, and open
  832. ;the next  location. A <CR> closes the current 
  833. ;location and quits. Typing bad hex aborts the 
  834. ;current location.
  835. ;
  836. memchg:
  837.     call    getadr        ;get start addr
  838. memal:    call    crlf
  839.     call    outadr        ;type address,
  840.     mov    dmpoff,bx    ;save addr,
  841.     mov    al,es:[bx]    ;get old,
  842.     call    out2h        ;type old,
  843.     mov    al,es:[bx]
  844.     mov    bl,al        ;put old in bl,
  845.     call    inhex        ;maybe get new,
  846.     mov    dh,bl        ;put new in dh,
  847.     mov    bx,dmpoff    ;get addr again
  848.     mov    es:[bx],dh    ;write to mem
  849.     cmp    al,CR        ;was char a CR?
  850.     jz    sret        ;exit    if so.
  851.     inc    bx        ;next location.
  852.     cmp    al,LF        ;if it was LF, 
  853.     jnz    memal        ;dec instead of
  854.     dec    bx        ;incrementing.
  855.     dec    bx
  856.     jmp    memal
  857. sret:    ret
  858. page
  859. ;
  860. ;fill memory with al number. get two addresses,
  861. ;then the filler. Cannot fill across segment
  862. ;boundaries.
  863. ;
  864. fill:    cld
  865.     call    getadr
  866.     call    inhex        ;get 2nd addr
  867.     cmp    al,':'        ;dont allow 2nd
  868.     jne    fllok        ;segment,
  869.         jmp    error    ;count 64k max.
  870. fllok:    mov    cx,dmpoff    ;cx is lo addr,
  871.     sub    bx,cx        ;bx is hi addr,
  872.     xchg    bx,cx        ;cx is count, 
  873.     push    bx        ;bx is lo addr
  874.     call    ghex0        ;get fill char,
  875.     mov    al,bl
  876.     pop    di        ;get addr,
  877.     jcxz    sret        ;dont do none,
  878.     rep stosb        ;do it.
  879.     ret
  880. ;
  881. ;Move a block of memory. Get the <from>, <end>
  882. ;and <to> addresses, calculate the block length
  883. ;then move it. Moves correctly across segments.
  884. ;
  885. blkmov:    cld
  886.     call    getadr        ;get from,
  887.     mov    dx,ES        ;save seg,
  888.     mov    si,bx
  889.     call    inhex        ;get end,
  890.     cmp    al,':'        ;dont allow a
  891.     jne    blk1        ;segment here,
  892.         jmp    error    ;error!
  893. blk1:    mov    cx,si
  894.     sub    bx,cx        ;cnt=end-from
  895.     mov    cx,bx
  896.     call    getadr        ;get to,
  897.     mov    di,bx        ;ES is dest seg
  898.     push    ds        ;save our DS
  899.     mov    ds,dx        ;set our temp
  900.     rep movsb         ;source    segment
  901.     pop    ds        ;restore DS
  902.     ret
  903. page
  904. ;
  905. ;Port I/O commands. These do 16    bit I/O    ports,
  906. ;but only 8 bit    data.
  907. ;
  908. ;    Input data from a port.
  909. ;
  910. input:
  911.     call    ghex0        ;get port num
  912.     mov    dx,bx
  913.     in    al,dx        ;read the port,
  914.     push    ax
  915.     call    crlf
  916.     pop    ax
  917.     push    ax
  918.     call    out2h        ;display in hex
  919.     pop    ax
  920.     call    altobin        ;then in binary
  921.     ret
  922.  
  923. ;
  924. ;    Output data to a port.
  925. ;
  926. output:
  927.     call    ghex0        ;get port num
  928.     mov    dx,bx
  929.     call    ghex0        ;get the data,
  930.     mov    ax,bx
  931.     out    dx,al        ;send it.
  932.     ret
  933. ;
  934. ;Do some simple    hex arithmetic.    Input an 
  935. ;expression, display the result.
  936. ;
  937. arith:    call    inhex        ;get the number
  938.     call    crlf        ;newline,
  939.     call    outhex        ;display result
  940.     ret
  941. page
  942. ;
  943. ;Load an intel hex file    from the console. This 
  944. ;does not support any extended hex format; just
  945. ;the old fashioned 8 bit hex. The segment is 
  946. ;input from the    console.
  947. ;
  948. intel:    mov    dmpoff,0    ;set defaults,
  949.     mov    dmpseg,40h
  950.     call    getadr        ;get load seg,
  951.     mov    es,dmpseg
  952. ;
  953. ;Load each hex record to segment ES, with an 
  954. ;offset    of (dmpoff)( i.e. added    to the specifie
  955. ;load address every time)
  956. ;
  957. getrcd:    call    charin        ;wait for colon
  958.     cmp    al,':'
  959.     je    iproc
  960.     cmp    al,LF        ;if LF, echo it
  961.     jne    getrcd
  962.     call    charout
  963.     jmp    getrcd
  964.  
  965. iproc:    mov    dx,0        ;clear checksum
  966.     call    in2        ;get the count,
  967.     mov    cl,bl        ;put in    CX,
  968.     mov    ch,0
  969.     call    in2        ;get load addr
  970.     mov    al,bl        ;save hi addr,
  971.     call    in2
  972.     mov    bh,al        ;assemble word,
  973.     mov    di,bx        ;put in    DI,
  974.     call    in2        ;record type,
  975.     cmp    bl,1        ;EOF?
  976.     jz    itret        ;return    if so,
  977.     jcxz    itret        ;or if no data,
  978. ;
  979. ;Read <CX> bytes to memory.
  980. ;
  981.     add    di,dmpoff    ;add in    offset,
  982. getb:    call    in2        ;get a byte,
  983.     mov    es:[di],bl    ;store it,
  984.     inc    di        ;next address,
  985.     loop    getb
  986.     call    in2        ;get check sum,
  987. ;
  988. ;checksum broken. Too lazy to fix it.
  989. ;
  990. ;    add    dl,bl        ;if OK,
  991. ;    jz    getrcd        ;repeat,
  992.     jmp    getrcd        ;patch fix.
  993.  
  994. iterr:    jmp    error        ;else error.
  995. itret:    ret
  996. page
  997. ;
  998. ;INTEL,    continued.
  999. ;
  1000. ;
  1001. ;Input the next    two digits as hex, return in 
  1002. ;BL. Accumulate    a checksum in DX, preserve 
  1003. ;AX, CX.
  1004. ;
  1005. in2:    push    ax
  1006.     push    cx
  1007.     mov    bx,0
  1008.     call    charin        ;get a char,
  1009.     call    hexin        ;install char,
  1010.     jb    iterr
  1011.     call    charin
  1012.     call    hexin
  1013.     jb    iterr
  1014.     pop    cx
  1015.     pop    ax
  1016.     add    dl,bl        ;checksum
  1017.     ret    
  1018. page
  1019. ;
  1020. ;Examine/change an interrupt vector. The
  1021. ;input number is checked for 0-ff, the 
  1022. ;address of it made, the contents displayed.
  1023. ;The contents can be changed by typing in
  1024. ;the new seg:off, or CR to leave unchanged.
  1025. ;
  1026. intvec:    call    ghex0        ;get int num,
  1027.     call    crlf        ;newline,
  1028.     and    bx,255        ;0-255,
  1029.     shl    bx,1        ;times 2,
  1030.     shl    bx,1        ;times 4,
  1031.     mov    ax,0
  1032.     mov    es,ax        ;seg 0,
  1033.     push    bx        ;save vec addr
  1034.     push    es        ;in es:BX,
  1035.     push    ip_base        ;relocation
  1036.     mov    ip_base,0    ;off,
  1037.     call    outadr        ;display addr,
  1038.  
  1039.     mov    ax,es:[bx+2]    ;get int seg,
  1040.     mov    bx,es:[bx]    ;get int off,
  1041.     mov    es,ax        ;to es:BX 
  1042.  
  1043.     mov    dmpseg,es    ;Set default
  1044.     mov    dmpoff,bx    ;for 'getadr',
  1045.     call    outadr        ;display it,
  1046.     call    getadr        ;get new,
  1047.     mov    cx,es        ;copy es:BX to 
  1048.     mov    dx,bx        ;CX:DX,
  1049.  
  1050.     pop    ip_base        ;restore reloc,
  1051.     pop    es        ;get back int
  1052.     pop    bx        ;vector addr,
  1053.     mov    es:[bx+2],cx    ;store new
  1054.     mov    es:[bx],dx    ;vector.
  1055.     ret
  1056. page
  1057. ;
  1058. ;Boot either a hard disk or floppy. Get either
  1059. ;'f', 'h' or 'm', then a number. Attempt to 
  1060. ;read the boot sector to memory, then execute 
  1061. ;it, unless the number has bit 15 set.
  1062. ;
  1063. dboot:    call    charin        ;get disk,
  1064.     mov    si,offset btbl    ;search table
  1065. db1:    cmp    al,cs:[si]    ;find it?
  1066.     je    db2
  1067.     add    si,blen        ;no, next..
  1068.     cmp    byte ptr cs:[si],0
  1069.     jne    db1        ;no more?
  1070.     jmp    error
  1071.  
  1072. db2:    call    ghex0        ;get number,
  1073.  
  1074.     mov    ax,cs        ;disk tables
  1075.     mov    ds,ax        ;in code seg
  1076.     push    bx        ;save it,
  1077.     mov    bx,cs:[si + 1]    ;disk table
  1078.     call    word ptr cs:[si + 3] ;read disk
  1079.     pop    cx
  1080.     mov    ds,cs:dataloc    ;set DS
  1081.     mov    bx,offset dskstr
  1082.     jc    db4        ;if OK,
  1083.  
  1084.     test    cx,8000h    ;and MSB set,
  1085.     jz    db3
  1086.     jmp    warm        ;dont boot
  1087. db3:    mov    bx,bootseg    ;look at 
  1088.     mov    es,bx        ;1st instruct,
  1089.     mov    bx,0        ;must be CLI,
  1090.     cmp    byte ptr es:[bx],0fah
  1091.     mov    bx,offset butstr
  1092.     jne    db4
  1093.  
  1094.     call    boot        ;attempt it,
  1095.     mov    bx,offset dskstr
  1096.  
  1097. db4:    call    pstr
  1098.     jmp    warm
  1099.  
  1100. btbl    db    'f'
  1101.     dw    dd1024
  1102.     dw    offset cgroup:execute
  1103. blen = $ - btbl
  1104.  
  1105.     db    'd'
  1106.     dw    dd1024
  1107.     dw    offset cgroup:execute
  1108.  
  1109.     db    's'
  1110.     dw    sd128
  1111.     dw    offset cgroup:execute
  1112.  
  1113.     db    'h'
  1114.     dw    rms
  1115.     dw    offset cgroup:dtc
  1116.  
  1117.     db    'm'
  1118.     dw    ibm
  1119.     dw    offset cgroup:execute
  1120.  
  1121.     db    0
  1122. page
  1123. ;
  1124. ;get an    address, or use    dump address. If a 
  1125. ;segment is specified, set ES. Return AL =
  1126. ;delimeter character.
  1127. ;
  1128. ;This adds ip_base to BX before    return.    RR 
  1129. ;defaults to 0000 at power up. Does not    affect
  1130. ;dmpoff    so that    setting    RR to 0000 again
  1131. ;correctly displays the    right value.
  1132. ;
  1133. getadr:    mov    ah,1        ;set flag,
  1134.     mov    bx,dmpseg    ;default seg
  1135.     call    inhex        ;if we set seg
  1136.     cmp    al,':'
  1137.     jne    setadr
  1138.         mov    dmpseg,bx ;update ES,
  1139.         mov    ES,bx
  1140.         mov    bx,dmpoff
  1141.         call    inhex    ;then set the 
  1142.         jmp    gtaret    ;address,
  1143. setadr:    dec    ah        ;not seg, if BX
  1144.     jnz    gtaret        ;changed return
  1145.     mov    bx,dmpoff    ;new else get 
  1146. gtaret:    mov    dmpoff,bx    ;old number,
  1147.     test    noreloc,1    ;if flag set,
  1148.     jnz    gtret        ;dont offset.
  1149.     add    bx,ip_base    ;add in    offset,
  1150. gtret:    ret
  1151. ;
  1152. ; type bx as hex, followed by a space.
  1153. ;
  1154. outhex:    call    typehex
  1155.     jmp    o2spc
  1156. typehex:mov    al,bh        ; most first
  1157.     call    out2
  1158.     mov    al,bl        ; do least
  1159.     call    out2
  1160.     ret
  1161. ;
  1162. ;display an address; SSSS:AAAA
  1163. ;
  1164. outadr:    push    bx
  1165.     mov    bx,es        ;print 
  1166.     call    typehex        ;segment:offset
  1167.     mov    al,':'
  1168.     call    charout
  1169.     pop    bx        ;save BX,
  1170.     push    bx
  1171.     sub    bx,ip_base    ;adjust    for
  1172.     call    outhex        ;display,
  1173.     pop    bx        ;restore,
  1174.     ret
  1175. page
  1176. ;
  1177. ;type al as hex.
  1178. ;
  1179. out2:    push    ax
  1180.     push    cx
  1181.     mov    cl,4
  1182.     shr    al,cl
  1183.     pop    cx
  1184.     call    out1h
  1185.     pop    ax
  1186. ;
  1187. ;type lsnybble of al.
  1188. ;
  1189. out1h:    and    al,0fh        ;only ls 4 bits
  1190.     or    al,'0'        ; make ascii
  1191.     cmp    al,'9'+1
  1192.     jb    out1
  1193.     add    al,'a'-'9'-1    ; 0-9,al-f
  1194. out1:    jmp    charout
  1195. ;
  1196. ; output al as hex followed by a space.
  1197. ;
  1198. out2h:    call    out2        ;type al in hex
  1199. ;
  1200. ;type a    space
  1201. ;
  1202. o2spc:    mov    al,' '
  1203.     jmp    out1
  1204. page
  1205. ;
  1206. ;Input a hex  into BX, default the number to 
  1207. ;zero.
  1208. ;
  1209. ghex0:
  1210.     mov    bx,0        ;fall through
  1211. ;
  1212. ;Input a hex number to BX. If only a delimiter 
  1213. ;is typed, return with no change in BX or AH. 
  1214. ;If any    number is input, AH is cleared.    
  1215. ;Supports the following    special    characters:
  1216. ;
  1217. ;    .<reg>    value of register <reg>
  1218. ;    +<xxxx>    sum of current value and 
  1219. ;        additional value <xxxx> + may 
  1220. ;        be entered after any number of 
  1221. ;        digits are typed, including dot
  1222. ;    -    same as    above, except 
  1223. ;        difference of 1st and 2nd value
  1224. ;        (first-second)
  1225. ;    *    Return theproduct of the current
  1226. ;        number and the next entered
  1227. ;        number.
  1228. ;    !    Suppresses relocation of offset
  1229. ;        by GETADR. Cleared on each call.
  1230. ;
  1231. ;Be careful when changing, as it uses 
  1232. ;recursion. Note that 'scratch' stores the LAST
  1233. ;delimiter and is not saved each iteration. 
  1234. ;Jumps to error if anything goes wrong.
  1235. ;
  1236. inhex:    mov    noreloc,0    ;clear flag,
  1237.     call    charin        ;get char 
  1238.     jne    inha        ;exit on CR,
  1239.         jmp    inhret
  1240. inha:    mov    bx,0        ;else seed it
  1241.  
  1242. inhb:    mov    ah,0        ;mark changed.
  1243.     cmp    al,'+'        ;check special 
  1244.     jne    inm        ;chars,    if plus
  1245.         push    bx    ;save current,
  1246.         call    inhex    ;get another,
  1247.         mov    scratch,al ;save delim,
  1248.         pop    ax
  1249.         add    bx,ax    ;add in    new one
  1250. ;splice after "ah,0    "
  1251.         mov    ah,0    ;change flag,
  1252.         mov    al,scratch ;get    delim
  1253.         ret        ;return    now.
  1254.  
  1255. inm:    cmp    al,'-'        ;if minus,
  1256.     jne    instar
  1257.         push    bx    ;save first val
  1258.         call    inhex    ;get second,
  1259.         mov    scratch,al ;save delim
  1260.         mov    ax,bx
  1261.         pop    bx
  1262.         sub    bx,ax    ;first-second,
  1263.         mov    ah,0
  1264.         mov    al,scratch
  1265.         ret
  1266.  
  1267. instar:    cmp    al,'*'        ;if star,
  1268.     jne    indot
  1269.         push    cx    ;save regs,
  1270.         push    dx
  1271.         push    bx    ;save current,
  1272.         call    inhex    ;get next,
  1273.         mov    scratch,al ;save delim,
  1274.         pop    ax    ;get last,
  1275.         mov    cx,bx    ;mult to CX,
  1276.         mul    cx    ;product,
  1277.         mov    bx,ax    ;to BX,
  1278.         pop    dx
  1279.         pop    cx    ;restore,
  1280.         mov    al,scratch
  1281.         mov    ah,0    ;BX changed.
  1282.         ret
  1283.     
  1284. indot:    cmp    al,'.'        ;if dot, use 
  1285.     jne    insup        ;a register,
  1286.         call    regval    ;get reg value,
  1287.         jnc    indot1    ;if not found,
  1288.             jmp    error
  1289. indot1:        mov    ah,0
  1290.         jmp    nxtchr
  1291. insup:    cmp    al,'!'        ;if suprise,
  1292.     jne    notspec
  1293.         mov    noreloc,1 ;suppress off
  1294.         jmp    nxtchr
  1295. notspec:call    hexin        ;digit to hl,
  1296.     jae    nxtchr        ;hex error?
  1297.         jmp    error    ;garbage.
  1298. nxtchr:    call    charin        ;another char 
  1299.     jnz    inhb        ;continue,
  1300.     ret            ;until a delim.
  1301. page
  1302. ;
  1303. ;check the char    in (al)    for hex, return    carry 
  1304. ;if not. install digit into bx.
  1305. ;
  1306. hexin:    sub    al,'0'        ;make hex,
  1307.     jz    hin        ;ok if 0,
  1308.     jb    inhret        ;if .lt. 0,
  1309. hxc:    cmp    al,10        ;do if .le. 9,
  1310.     jb    hin
  1311.     sub    al,27h        ;if a-f, hex.
  1312.     cmp    al,16        ;carry if below
  1313.     cmc            ;now carry if 
  1314.     jb    inhret        ;above,
  1315. hin:
  1316.     add    bx,bx        ;times 16,
  1317.     add    bx,bx
  1318.     add    bx,bx
  1319.     add    bx,bx
  1320.     or    bl,al        ;add in    digit,
  1321.     clc            ;no error.
  1322. inhret:    ret
  1323. ;
  1324. ;Get the ASCII name of a register, and return
  1325. ;it's current value in BX. Return carry set if
  1326. ;not a legal register.
  1327. ;
  1328. regval:    push    si
  1329.     push    cx
  1330.     call    charin        ;get 1st char,
  1331.     mov    ah,al        ;MS byte,
  1332.     call    charin        ;AX is name,
  1333.     cmp    ax,'ip'        ;special case
  1334.     je    retip        ;IP,
  1335.  
  1336.     mov    si,offset regtbl;reg names,
  1337.     mov    bx,offset dmp_ptr; reg values,
  1338.     mov    cx,rtblen
  1339. rv1:    cmp    ax,cs:[si]    ;match?
  1340.     je    rv2        ;go change.
  1341.     add    si,2        ;next...
  1342.     add    bx,2
  1343.     loop    rv1
  1344.     stc            ;not found,
  1345.     jmp    rv3        ;return error.
  1346.  
  1347. rv2:    mov    bx,[bx]        ;get value,
  1348.     clc            ;return good,
  1349. rv3:    pop    cx        ;restore,
  1350.     pop    si
  1351.     ret
  1352. ;
  1353. ;Return the value of IP adjusted by 'ip_base'.
  1354. ;
  1355. retip:    mov    bx,brkip
  1356.     sub    bx,ip_base
  1357.     clc
  1358.     jmp    rv3
  1359. page
  1360. ;
  1361. ;Type ax in binary. 
  1362. ;
  1363. axtobin:mov    cx,16
  1364.     jmp    nnbit
  1365. ;
  1366. ;Type al in binary. Type 1's as 1, 0's as 0.
  1367. ;
  1368. altobin:mov    cx,8
  1369.     mov    ah,al
  1370. nnbit:    mov    dl,'0'
  1371.     shl    ax,1
  1372.     adc    dl,0
  1373.     push    ax
  1374.     mov    al,dl
  1375.     call    charout
  1376.     pop    ax
  1377.     loop    nnbit
  1378.     jmp    o2spc
  1379. ;
  1380. ; print    a string.
  1381. ;
  1382. pstr:    mov    al,cs:[bx]
  1383.     test    al,al
  1384.     je    psret
  1385.     call    charout        ;type until a 0
  1386.     inc    bx
  1387.     jmp    pstr
  1388. ;
  1389. ;do a crlf
  1390. ;
  1391. crlf:    mov    al,cr
  1392.     call    charout
  1393. psret:    ret
  1394. page
  1395. ;
  1396. ;Wait for a character, and return in AL. Leave
  1397. ;the Z bit set if the char is one of our
  1398. ;delimiters. Convert to    lower case.
  1399. ;
  1400. charin:
  1401.     call    INA        ;get one char
  1402.     and    al,7Fh
  1403.     cmp    al,'9'+1    ;to lower 
  1404.     jb    chial        ;case,
  1405.     or    al,20h        ;set shift bit,
  1406. chial:    cmp    al,LF        ;dont echo LF's
  1407.     jz    inaret        ;return    Z set, 
  1408.     push    ax        ;indicate delim
  1409.     call    OUTA        ;echo it,
  1410.     pop    ax
  1411. ;
  1412. ;Here we check for the legal hexadecimal number
  1413. ;delimiters.
  1414. ;
  1415.     cmp    al,CR        ;check delim,
  1416.     jz    inaret
  1417.     cmp    al,','
  1418.     jz    inaret
  1419.     cmp    al,' '
  1420.     jz    inaret
  1421.     cmp    al,LF
  1422.     jz    inaret
  1423.     cmp    al,':'
  1424. inaret:    ret
  1425. ;
  1426. ;Output    a character to the console.
  1427. ;
  1428. charout:
  1429.     cmp    al,CR        ;if CR,    do a LF
  1430.     jnz    out
  1431.     call    out
  1432.     mov    al,LF
  1433. out:    call    OUTA
  1434.     ret
  1435. page
  1436. ;
  1437. ;init each device to the minimum necessary
  1438. ;to run the debugger. The BIOS will fully
  1439. ;init everything once booted.
  1440. ;
  1441. ioinit:    mov    al,8ah        ;8255 0, A out
  1442.     out    ppictl,al    ;B in C0-3 out
  1443.     mov    al,0        ;C4-7 in
  1444.     out    ppia,al        ;outputs off
  1445.  
  1446.     mov     al,0Eh
  1447.     call    set8251        ;dummy mode
  1448.     mov     al,40h
  1449.     call    set8251        ;reset 8251 
  1450.     mov     al,4Eh
  1451.     call    set8251        ;8 bt async *16
  1452.     mov     al,37h
  1453.     call    set8251        ;enable Tx & Rx
  1454.     mov     al,0B6h
  1455.     out     pitmode,al    ;ch.2 sq wave 
  1456.     mov     ax,baud
  1457.     out     pittmr2,al    ;low baud rate
  1458.     mov     al,ah 
  1459.     out     pittmr2,al    ;high baud rate
  1460. ;
  1461. ;Setup 8259 Programmable Interrupt Controller
  1462. ;
  1463.     mov     al,13h
  1464.     out     pici1,al    ;8086 mode
  1465.     mov     al,00h
  1466.     out     pici2,al    ;vector
  1467.     mov     al,1Fh
  1468.     out     pici2,al    ;EOI master
  1469.     mov     al,0FFh
  1470.     out     pici2,al    ;all levels off
  1471. page
  1472. ;
  1473. ;Initialize the RMS and DTC86. Do a 
  1474. ;considerable delay here, since I think theres
  1475. ;a problem with the Xebex powering up slowly.
  1476. ;
  1477.     mov    cx,-1
  1478. xdel:    jmp    $ + 2
  1479.     loop    xdel
  1480.     call    dskinit        ;init RMS disk,
  1481. ;
  1482. ;Initialize the floppy controller.
  1483. ;
  1484.     call    flpinit
  1485.     ret
  1486. ;
  1487. ;Set a control byte to the 8251, delaying 
  1488. ;after each one.
  1489. ;
  1490. set8251:
  1491.     out    pcimode,al
  1492.     mov    cx,100
  1493. s8:    jmp    $ + 2
  1494.     loop    s8
  1495.     ret
  1496. page
  1497. ;
  1498. ;Character drivers.
  1499. ;
  1500. ;
  1501. outa:    push     ax
  1502. opoll:    in     al,pcimode
  1503.     and     al,1
  1504.     jz     opoll
  1505.     pop     ax
  1506.     out     pcidata,al
  1507.     ret
  1508. ;
  1509. ;Input a character from the console. Turn
  1510. ;interrupts off, so we can get chars while
  1511. ;MSDOS is running.
  1512. ;
  1513. ina:    pushf
  1514.     cli
  1515. inw:    call     inastat
  1516.     jz     inw
  1517.     in     al,pcidata
  1518.     popf
  1519. inret:    ret
  1520.  
  1521.  
  1522. inastat:
  1523.     in     al,pcimode
  1524.     and     al,2
  1525.     ret
  1526. page
  1527. ;
  1528. ;Play a tune; BX points to a sound table.
  1529. ;
  1530. play:    mov    dx,cs:[bx]    ;get a note,
  1531.     mov    cx,cs:[bx + 2]    ;get duration
  1532.     add    bx,4
  1533.     cmp    dx,ENDNOTE    ;quit if end
  1534.     je    plz
  1535.     call    note
  1536.     jmp    play
  1537. plz:    ret
  1538. ;
  1539. ;Play a note; BX is the divisor, CX is the
  1540. ;duration. If the note is 0, pause.
  1541. ;
  1542. note:    mov    al,0
  1543.     out    ppic,al        ;sound off,
  1544.     cmp    dx,NONOTE    ;if a sound,
  1545.     je    sd1
  1546.     mov    al,36h        ;timer 0 mode 3
  1547.     out    pitmode,al
  1548.     mov    al,dl        ;select sound
  1549.     out    pittmr0,al
  1550.     mov    al,dh
  1551.     out    pittmr0,al
  1552.     mov    al,1
  1553.     out    ppic,al        ;enable sound,
  1554.  
  1555. sd1:    mov    ax,1000
  1556. sd2:    dec    ax        ;delay
  1557.     jnz    sd2
  1558.     loop    sd1
  1559.     mov    al,0        ;disable sound
  1560.     out    ppic,al
  1561.     ret
  1562. page
  1563. ;
  1564. ;Initialize the RMS disk and Xebec controller.
  1565. ;Assumes an RMS 512; this is adequate for
  1566. ;booting the system. The BIOS will init it
  1567. ;for the correct number of tracks, etc.
  1568. ;
  1569. cyls    equ    153        ;cylinders
  1570. heads    equ    8        ;heads,
  1571. comptrk    equ    77        ;precomp trk,
  1572. ecclen    equ    11        ;ECC length,
  1573. ;
  1574. ;initialization tables. These get copied to
  1575. ;RAM, so it can be DMA'd to the DTC.
  1576. ;
  1577. romtbl label byte
  1578.     db    12,0,0,0    ;init drv
  1579.     db    0,0,0,0,0    ;characteristic
  1580. ;
  1581. ;Initialization data.
  1582. ;
  1583.     db    high cyls
  1584.     db    low cyls
  1585.     db    heads
  1586.     db    high comptrk
  1587.     db    low comptrk
  1588.     db    high comptrk
  1589.     db    low comptrk
  1590.     db    ecclen
  1591. tblen equ $ - romtbl
  1592.  
  1593. dskinit:
  1594.     mov    bx,offset cmdtbl ;copy the 
  1595.     mov    si,offset romtbl ;table to RAM
  1596.     mov    cx,tblen    ;so we can DMA
  1597. dn1:    mov    al,cs:[si]
  1598.     mov    [bx],al
  1599.     inc    si
  1600.     inc    bx
  1601.     loop    dn1
  1602.  
  1603.     in    al,ccr        ;clr old DONE,
  1604.     mov    ax,ds
  1605.     mov    cx,16
  1606.     mul    cx
  1607.     add    ax,offset cmdtbl
  1608.     adc    dx,0
  1609.     out    cal,al
  1610.     mov    al,ah
  1611.     out    cah,al
  1612.     mov    al,dl
  1613.     out    cat,al
  1614.  
  1615.     mov    ax,ds
  1616.     mul    cx
  1617.     add    ax,offset dattbl
  1618.     adc    dx,0
  1619.     out    dal,al
  1620.     mov    al,ah
  1621.     out    dah,al
  1622.     mov    al,dl
  1623.     out    dat,al
  1624.  
  1625.     mov    al,0
  1626.     out    csr,al        ;start it,
  1627.     ret
  1628. page
  1629. ;
  1630. ;Intel iSBC 208 Diskette Controller.
  1631. ;
  1632. ;Floppy disk initialization. Set both drives
  1633. ;as in service, and set the step and settle
  1634. ;times for the NEC chip.
  1635. ;
  1636. flpinit:
  1637.     mov    dx,resp        ;reset port
  1638.     out    dx,al        ;hit it
  1639.     mov    cx,5000
  1640. di1:    jmp    $ + 2
  1641.     loop    di1        ;short delay
  1642.     mov    al,0
  1643.     mov    dx,dcmdp
  1644.     out    dx,al        ;DMA command
  1645.     mov    al,specc    ;specify,
  1646.     call    outcmd
  1647.     mov    al,srthut
  1648.     call    outcmd
  1649.     mov    al,hltnd
  1650.     call    outcmd
  1651.     ret
  1652. page
  1653. ;
  1654. ;Returns Z set if the drive was ready, with the
  1655. ;floppy status byte in DL. The caller must
  1656. ;perform additional error checking. 
  1657. ;
  1658. execute:
  1659.     out    dflp,al        ;first/last
  1660.     call    seldrv        ;select it,
  1661.     jc    rwz
  1662.     call    seek        ;seek track,
  1663.     jc    rwz        ;ret if error,
  1664.     call    diskio        ;try it,
  1665. rwz:    ret
  1666. ;
  1667. ;Put the count to the 8257, adding in the right
  1668. ;DMA direction bit, depending on the floppy
  1669. ;command.
  1670. ;
  1671. diskio:    mov    dx,0
  1672.     mov    ax,secsiz[bx]    ;make a DMA 
  1673.     mul    word ptr count[bx] ;count,
  1674.     dec    ax        ;-1 for DMA,
  1675.     mov    dx,ch0cp
  1676.     out    dx,al        ;out LS byte,
  1677.     mov    al,ah
  1678.     out    dx,al        ;out MS byte
  1679.  
  1680.     mov    al,dmarb    ;DMA read
  1681.     cmp    byte ptr command[bx],fwrite
  1682.     je    setdm        ;if disk write,
  1683.     mov    al,dmawb    ;else disk read
  1684. setdm:    mov    dx,modp        ;Mode Port,
  1685.     out    dx,al        ;output it,
  1686. ;
  1687. ;The 208 has a nice segment register. Just
  1688. ;output it.
  1689. ;
  1690.     mov    ax,dmaoff[bx]
  1691.     mov    dx,ch0ap
  1692.     out    dx,al
  1693.     mov    al,ah
  1694.     out    dx,al
  1695.  
  1696.     mov    ax,dmaseg[bx]
  1697.     mov    dx,seglp
  1698.     out    dx,al
  1699.     mov    al,ah
  1700.     mov    dx,seghp
  1701.     out    dx,al
  1702. page
  1703. ;
  1704. ;Issue the floppy command, and wait for 
  1705. ;completion. Return status in DL.
  1706. ;
  1707. adrok:    call    sense_int    ;flush FDC,
  1708.     mov    al,dmacb
  1709.     mov    dx,maskp    ;start DMA,
  1710.     out    dx,al
  1711.  
  1712. ak1:    mov    al,readc    ;assume read,
  1713.     mov    ah,0        ;single density
  1714.     cmp    byte ptr command[bx],fwrite
  1715.     jne    ak2
  1716.     mov    al,writec
  1717. ak2:    test    byte ptr density[bx],1
  1718.     jz    ak3
  1719.     mov    ah,40h
  1720. ak3:    or    al,ah
  1721.     call    drvcmd        ;cmd + drive,
  1722.     mov    al,track[bx]
  1723.     call    outcmd        ;track,
  1724.     mov    al,head[bx]
  1725.     call    outcmd        ;head,
  1726.     mov    al,sector[bx]
  1727.     call    outcmd        ;sector,
  1728.     mov    al,enn[bx]
  1729.     call    outcmd        ;recd size,
  1730.     mov    al,sector[bx]
  1731.     add    al,count[bx]    ;next recd,
  1732.     dec    al        ;last recd,
  1733.     call    outcmd        ;last sec,
  1734.     mov    al,gaplen[bx]
  1735.     call    outcmd        ;gap length,
  1736.     mov    al,dtl[bx]
  1737.     call    outcmd        ;data length,
  1738.  
  1739.     call    getresult    ;check results
  1740.     mov    al,4        ;"read error"
  1741.     jc    akz        ;nope, check
  1742.     and    ah,7fh        ;ST1,
  1743.     stc
  1744.     jnz    akz
  1745.     xor    al,al        ;no error
  1746. akz:    ret
  1747. page
  1748. ;
  1749. ;Select the drive, return carry set if not
  1750. ;ready. All this really does is select the
  1751. ;drive size, and force READY true if mini.
  1752. ;If the motor is off and this is a mini
  1753. ;floppy, turn it on and wait.
  1754. ;
  1755. seldrv:    mov    dx,drcp        ;control port
  1756.     mov    al,0        ;assume 8"
  1757.     test    byte ptr density[bx],2
  1758.     jz    sv1        ;else 5 1/4"
  1759.     mov    al,MTR + RDY + MINI
  1760. sv1:    out    dx,al        ;write it
  1761.     mov    cx,65535
  1762. sv2:    jmp    $ + 2
  1763.     loop    sv2
  1764.     ret
  1765. ;
  1766. ;Seek a track. If current track is unknown,
  1767. ;recal the drive first. Return carry set if 
  1768. ;error, with AL =6. (MSDOS seek error)
  1769. ;
  1770. seek:    mov    al,curtrk[bx]    ;if current
  1771.     cmp    al,255        ;unknown,
  1772.     jne    sk1        ;recal first,
  1773.     call    recal
  1774.     jc    sk2        ;quit if error,
  1775.     mov    al,0        ;at trk 0
  1776.  
  1777. sk1:    cmp    track[bx],al    ;if at track,
  1778.     je    skdn        ;dont seek
  1779.     mov    al,seekc    ;seek desired
  1780.     call    drvcmd        ;track,
  1781.     mov    al,track[bx]
  1782.     call    outcmd
  1783.     mov    cl,track[bx]    ;for compare,
  1784.     mov    ch,0f8h        ;status bits,
  1785.     call    complete
  1786. skdn:    ret
  1787. ;
  1788. ;Recal the disk.
  1789. ;
  1790. recal:    mov    al,recalc
  1791.     call    outcmd
  1792.     mov    al,drive[bx]
  1793.     call    outcmd        ;recal,
  1794.     mov    cl,0        ;new trk =0,
  1795.     mov    ch,20h        ;chk only seek,
  1796.     call    complete    ;check,
  1797.     xor    al,al        ;no errors!
  1798.     ret
  1799. page
  1800. ;
  1801. ;Issue command in AL, followed by the
  1802. ;drive number.
  1803. ;
  1804. drvcmd:    call    outcmd        ;send cmd byte,
  1805.     mov    al,head[bx]    ;make head bit,
  1806.     shl    al,1
  1807.     shl    al,1
  1808.     and    al,4        ;make it legal,
  1809.     or    al,drive[bx]    ;then add drive
  1810.     call    outcmd
  1811.     ret
  1812. ;
  1813. ;Wait for seek done, then check status.
  1814. ;
  1815. complete:
  1816.     call    sense_int    ;wait for done,
  1817.     cmp    ah,80h        ;wait for seek,
  1818.     je    complete
  1819.     and    ah,ch        ;chk completion
  1820.     cmp    ah,20h
  1821.     jne    sk2        ;return if bad
  1822.     cmp    al,cl        ;correct track?
  1823.     jnz    sk2        ;error if not,
  1824.     ret
  1825.  
  1826. sk2:    stc
  1827.     mov    al,6        ;"seek error"
  1828.     ret
  1829. ;
  1830. ;Sense interrupt status. Return ST0 in
  1831. ;AH, PCN in AL. (If no seek done, AH= 80h,
  1832. ;AL= 80h.) If we find a ready line change,
  1833. ;loop to clear it.
  1834. ;
  1835. sense_int:
  1836.     mov    al,skstc    ;get int status
  1837.     call    outcmd
  1838.     call    instat        ;get ST0,
  1839.     mov    ah,al        ;save it,
  1840.     cmp    ah,80h        ;if not pending
  1841.     je    siz        ;exit,
  1842.     call    instat        ;get PCN,
  1843.     push    ax
  1844.     and    ah,0c0h        ;if ready line,
  1845.     cmp    ah,0c0h        ;repeat,
  1846.     pop    ax
  1847.     je    sense_int
  1848. siz:    ret
  1849. page
  1850. ;
  1851. ;Output a byte to the FDC; delay, then wait
  1852. ;for RQM and DIO == 0. IF we find DIO true, ie.
  1853. ;bytes to read, read them just so we wont hang
  1854. ;forever.
  1855. ;
  1856. outcmd:    push    ax        ;save the byte
  1857. oc0:    call    delay
  1858.     mov    dx,fdcstat
  1859. oc1:    in    al,dx
  1860.     test    al,80h        ;wait for RQM
  1861.     jz    oc1
  1862.     mov    dx,fdcdata    ;DX = data port
  1863.     test    al,40h        ;if DIO = in,
  1864.     jz    oc2
  1865.     in    al,dx        ;flush input
  1866.     jmp    oc0        ;bytes (?!)
  1867.  
  1868. oc2:    pop    ax
  1869.     out    dx,al        ;output command
  1870.     ret
  1871. ;
  1872. ;Read an input byte from the 765. If it wants 
  1873. ;an output byte, well, feed it something, its
  1874. ;better than hanging forever.
  1875. ;
  1876. instat:    call    delay        ;slow ...
  1877. ic0:    mov    dx,fdcstat
  1878. ic1:    in    al,dx
  1879.     test    al,80h        ;RQM
  1880.     jz    ic1        ;wait for it
  1881.     mov    dx,fdcdata
  1882.     test    al,40h        ;DIO
  1883.     jnz    ic2        ;if DIO == 0
  1884.     out    dx,al        ;satisfy it
  1885.     jmp    ic0
  1886. ic2:    in    al,dx        ;read a byte
  1887.     ret
  1888. ;
  1889. ;Get result phase. Just get bytes until there 
  1890. ;are no more. Return carry set if we dont get
  1891. ;exactly seven input bytes. We return ST1 in AH
  1892. ;and throw away the rest.
  1893. ;
  1894. getresult:
  1895.     mov    cx,0        ;bytes read
  1896.     mov    ah,0ffh        ;ST1
  1897.     call    delay
  1898.  
  1899. gr1:    mov    dx,fdcstat    ;wait for RQM
  1900.     in    al,dx
  1901.     test    al,80h
  1902.     jz    gr1
  1903.  
  1904.     test    al,40h        ;DIO set?
  1905.     jz    gr2
  1906.     mov    dx,fdcdata    ;read a byte
  1907.     in    al,dx
  1908.     cmp    cx,1        ;2nd byte?
  1909.     jne    gr1a
  1910.     mov    ah,al        ;save ST1
  1911. gr1a:    inc    cx        ;count it,
  1912.     jmp    gr1
  1913.  
  1914. gr2:    sub    cx,7        ;check for < 7,
  1915.     ret
  1916. ;
  1917. ;Software delay for use with fast 8086's.
  1918. ;
  1919. delay:    push    cx        ;11
  1920.     mov    cx,40        ;(4 to 8) * 40,
  1921. dly:    jmp    $ + 2        ;clear the queue
  1922.     loop    dly        ;17/5
  1923.     pop    cx        ;8
  1924.     ret            ;8
  1925. page
  1926. ;
  1927. ;DTC-86 / Xebec Controller driver. This assumes
  1928. ;an RMS drive attached as drive 0.
  1929. ;Accepts a standard Fido disk table at
  1930. ;DS:BX, performs the function, returns
  1931. ;status in carry and AL.
  1932. ;
  1933. ;
  1934. ;Perform the IO, return carry set and an MSDOS
  1935. ;error code in AL if failure.
  1936. ;
  1937. dtc:    push    ds        ;point ES to
  1938.     pop    es        ;cmd block,
  1939.     push    ds
  1940.     mov    ds,cs:dataloc    ;set DS,
  1941.     mov    ax,ds        ;set cmd addr
  1942.     mov    cx,16
  1943.     mul    cx        ;20 bit addr
  1944.     add    ax,offset xcomand
  1945.     adc    dx,0
  1946.     out    cal,al        ;out 3 bytes,
  1947.     call    delay
  1948.     mov    al,ah
  1949.     out    cah,al
  1950.     call    delay
  1951.     mov    al,dl
  1952.     out    cat,al
  1953.     call    delay
  1954.  
  1955.     mov    ax,es:dmaseg[bx]
  1956.     mul    cx        ;same for data
  1957.     add    ax,es:dmaoff[bx]
  1958.     adc    dx,0
  1959.     out    dal,al        ;out 3 bytes,
  1960.     call    delay
  1961.     mov    al,ah
  1962.     out    dah,al
  1963.     call    delay
  1964.     mov    al,dl
  1965.     out    dat,al
  1966.     call    delay
  1967. page
  1968. ;
  1969. ;Calculate the logical sector, put it in the
  1970. ;table.
  1971. ;
  1972.     mov    ax,es:track[bx]    ;AX= track,
  1973.     mov    dx,0
  1974.     mul word ptr es:spt[bx]    ; *SPT,
  1975.     mov    cx,es:sector[bx]
  1976.     dec    cx        ;make 0-N,
  1977.     add    ax,cx
  1978.     adc    dx,0
  1979.  
  1980.     mov    lowaddr,al    ;store low,
  1981.     mov    hiaddr,ah    ;high sec,
  1982.     and    dl,0fh        ;top sec,
  1983.  
  1984.     mov    al,es:drive[bx]    ;make LUN,
  1985.     mov    cl,5
  1986.     shl    al,cl
  1987.     or    al,dl        ;add in,
  1988.     mov    lun,al        ;store it,
  1989.  
  1990.     mov    control,4     ;type =RMS,
  1991.     mov    ax,es:count[bx]
  1992.     mov    scount,al     ;set sec count,
  1993.  
  1994.     mov    al,es:command[bx]
  1995. ;    mov    xcomand,xwrite
  1996. ;    cmp    al,fwrite
  1997. ;    je    dtc1
  1998.     mov    xcomand,xread
  1999.     cmp    al,fread
  2000.     je    dtc1
  2001.     mov    xcomand,xcheck
  2002.     cmp    al,fcheck
  2003.     je    dtc1
  2004.     stc            ;illegal cmd
  2005.     jmp    dtc3
  2006.  
  2007. dtc1:    in    al,ccr        ;clear old done
  2008.     mov    al,0
  2009.     out    csr,al        ;start it,
  2010.  
  2011. dtc2:    call    delay
  2012.     in    al,csr        ;wait for DONE,
  2013.     test    al,80h
  2014.     jz    dtc2
  2015.     call    delay
  2016.     in    al,ccr        ;sample ERROR,
  2017.     and    al,2        ;clears DONE,
  2018.     jz    dtc3
  2019.     stc            ;error!
  2020. dtc3:    pop    ds
  2021.     ret
  2022.  
  2023. code ends
  2024.  
  2025.     end    bugger
  2026.